# ResolvedManyToManyRelation.java

    package org.codefilarete.stalactite.engine.configurer.model;

    import java.util.Collection;
    import java.util.function.Supplier;

    import org.codefilarete.reflection.ReadWritePropertyAccessPoint;
    import org.codefilarete.stalactite.dsl.property.CascadeOptions.RelationMode;
    import org.codefilarete.stalactite.engine.runtime.IndexedAssociationTable;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.result.BeanRelationFixer;

    /**
     * {@link ComponentRelation} dedicated to many-to-many.
     * Many-to-many relations always use an intermediary association table, represented as an
     * {@link IntermediaryRelationJoin}.  When the table carries a positional index column
     * ({@link IndexedAssociationTable}), {@link #isOrdered()} returns {@code true}.
     *
     * @param <SRC>        the entity type owning the collection
     * @param <TRGT>       the entity type stored in the collection
     * @param <S>          the collection type
     * @param <SRCID>      the source entity identifier type
     * @param <TRGTID>     the target entity identifier type
     * @param <LEFTTABLE>  the source table type
     * @param <RIGHTTABLE> the target table type
     * @author Guillaume Mary
     */
    public class ResolvedManyToManyRelation<
    		SRC, TRGT,
    		S extends Collection<TRGT>,
    		SRCID, TRGTID,
    		LEFTTABLE extends Table<LEFTTABLE>,
    		RIGHTTABLE extends Table<RIGHTTABLE>>
    		extends ComponentRelation<SRC, TRGT, S, LEFTTABLE, RIGHTTABLE, SRCID> {

    	private final Entity<TRGT, TRGTID, RIGHTTABLE> targetEntity;

    	public ResolvedManyToManyRelation(Entity<TRGT, TRGTID, RIGHTTABLE> targetEntity,
    	                                  ReadWritePropertyAccessPoint<SRC, S> accessor,
    	                                  RelationMode relationMode,
    	                                  boolean fetchSeparately,
    	                                  IntermediaryRelationJoin<LEFTTABLE, RIGHTTABLE, ?, SRCID, TRGTID> join,
    	                                  BeanRelationFixer<SRC, TRGT> beanRelationFixer,
    	                                  Supplier<S> collectionFactory) {
    		super(accessor, relationMode, fetchSeparately, join, beanRelationFixer, collectionFactory);
    		this.targetEntity = targetEntity;
    	}

    	public Entity<TRGT, TRGTID, RIGHTTABLE> getTargetEntity() {
    		return targetEntity;
    	}

    	/**
    	 * Returns {@code true} when the underlying association table carries a positional index column,
    	 * meaning the collection order must be preserved during SELECT.
    	 */
    	public boolean isOrdered() {
    		return ((IntermediaryRelationJoin<?, ?, ?, ?, ?>) getJoin()).getJoinTable() instanceof IndexedAssociationTable;
    	}

    	/**
    	 * Returns the index column of the association table.
    	 * Only meaningful when {@link #isOrdered()} is {@code true}.
    	 *
    	 * @param <ASSOCIATIONTABLE> the concrete indexed association table type
    	 * @return the index {@link Column}, or {@code null} when the relation is not ordered
    	 */
    	@SuppressWarnings("unchecked")
    	public <ASSOCIATIONTABLE extends IndexedAssociationTable<ASSOCIATIONTABLE, LEFTTABLE, RIGHTTABLE, SRCID, TRGTID>>
    	Column<ASSOCIATIONTABLE, Integer> getIndexingAssociationColumn() {
    		return ((ASSOCIATIONTABLE) ((IntermediaryRelationJoin<?, ?, ?, ?, ?>) getJoin()).getJoinTable()).getIndexColumn();
    	}
    }